﻿using Mapster;
using MaterialDesignThemes.Wpf;
using Minotaur.App.Core;
using Minotaur.App.Core.Attributes;
using Minotaur.App.Domains.Dto;
using Minotaur.App.Domains.Model.Account;
using Minotaur.App.Domains.Model.Menu;
using Minotaur.App.Domains.Model.Role;
using Minotaur.App.Domains.ViewModel.Menu;
using Newtonsoft.Json;
using ServiceStack;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Minotaur.App.Modules.Business.Service.Mneu
{
    public class MenuInfoListService : IMenuInfoListService
    {
        private readonly IDbContext dbContext;
        private readonly GlobalUserModel userModel;

        public MenuInfoListService(IDbContext dbContext, GlobalUserModel userModel)
        {
            this.dbContext = dbContext;
            this.userModel = userModel;
        }
        [GlobalLogAspect]
        public async Task<List<MenuInfoDto>> GenerateMenuInfo()
        {
            List<MenuInfoDto> menuInfoDtos = new List<MenuInfoDto>();
            int lan = (int)((userModel.Language + "").ConvertEnumEvent<Domains.Enum.LanguageType>());
            if (userModel.IsAdmin)
                menuInfoDtos = await this.dbContext.BusinessDb.Queryable<MenuInfo>()
                             .LeftJoin<MenuRes>((a, b) => a.AutoId == b.MenuId && b.Lan == lan)
                             .Where((a, b) => a.Status.Value)
                             .Select((a, b) => new MenuInfoDto()
                             {
                                 Address = a.Address,
                                 Code = a.Code,
                                 Icon = a.Icon,
                                 Name = b.Value,
                                 ParentCode = a.ParentCode,
                                 Sequence = a.Sequence,
                                 Status = a.Status,
                             }).ToListAsync();
            else
                menuInfoDtos = await this.dbContext.BusinessDb.Queryable<MenuInfo>().
                     InnerJoin<MenuRole>((a, b) => a.AutoId == b.MenuId)
                     .InnerJoin<RoleEmployeeInfo>((a, b, c) => b.RoleId == c.RoleId)
                     .LeftJoin<MenuRes>((a, b, c, d) => a.AutoId == d.MenuId && d.Lan == lan)
                     .Where((a, b, c, d) => c.EmpId == userModel.EmpId && a.Status.Value)
                     .Select((a, b, c, d) => new MenuInfoDto()
                     {
                         Address = a.Address,
                         Code = a.Code,
                         Icon = a.Icon,
                         Name = d.Value,
                         ParentCode = a.ParentCode,
                         Sequence = a.Sequence,
                         Status = a.Status,
                     }).ToListAsync();
            List<MenuInfoDto> resultMenuInfo = new List<MenuInfoDto>();
            if (menuInfoDtos.Any())
            {
                foreach (var item in menuInfoDtos.OrderBy(o => o.Sequence).Where(O => string.IsNullOrEmpty(O.ParentCode)))
                {
                    List<BussineKeyValueDto> dtos = JsonConvert.DeserializeObject<List<BussineKeyValueDto>>(item.Icon);
                    if (dtos.Any(o => o.Label == "pc"))
                    {
                        item.IconKind = (PackIconKind)int.Parse(dtos.FirstOrDefault(o => o.Label == "pc").Value ?? "0");
                    }
                    foreach (var oitem in menuInfoDtos.Where(o => o.ParentCode == item.Code))
                    {
                        dtos = JsonConvert.DeserializeObject<List<BussineKeyValueDto>>(oitem.Icon);
                        if (dtos.Any(o => o.Label == "pc"))
                        {
                            oitem.IconKind = (PackIconKind)int.Parse(dtos.FirstOrDefault(o => o.Label == "pc").Value ?? "0");
                        }
                        foreach (var tItem in menuInfoDtos.Where(o => o.ParentCode == oitem.Code))
                        {
                            dtos = JsonConvert.DeserializeObject<List<BussineKeyValueDto>>(tItem.Icon);
                            if (dtos.Any(o => o.Label == "pc"))
                            {
                                tItem.IconKind = (PackIconKind)int.Parse(dtos.FirstOrDefault(o => o.Label == "pc").Value ?? "0");
                            }
                            foreach (var fItem in menuInfoDtos.Where(o => o.ParentCode == tItem.Code))
                            {
                                dtos = JsonConvert.DeserializeObject<List<BussineKeyValueDto>>(fItem.Icon);
                                if (dtos.Any(o => o.Label == "pc"))
                                {
                                    fItem.IconKind = (PackIconKind)int.Parse(dtos.FirstOrDefault(o => o.Label == "pc").Value ?? "0");
                                }
                                fItem.ModuleCode = item.Code;
                                tItem.Childs.Add(fItem);
                            }
                            tItem.ModuleCode = item.Code;
                            oitem.Childs.Add(tItem);
                        }
                        oitem.ModuleCode = item.Code;
                        item.Childs.Add(oitem);
                    }
                    item.ModuleCode = item.Code;
                    resultMenuInfo.Add(item);
                }
            }
            return resultMenuInfo;
        }

        /// <summary>
        /// 获取所有的菜单
        /// </summary>
        /// <returns></returns>
        [GlobalLogAspect]
        public async Task<List<MenuInfoListDto>> InitMenuInfosAsync()
        {
            int lan = (int)((userModel.Language + "").ConvertEnumEvent<Domains.Enum.LanguageType>());
            List<MenuInfoListDto> menus = new List<MenuInfoListDto>();

            if (userModel.IsAdmin)
                menus = await dbContext.BusinessDb.Queryable<MenuInfo>()
                             .LeftJoin<MenuRes>((a, b) => a.AutoId == b.MenuId && b.Lan == lan)
                             .Select((a, b) => new MenuInfoListDto()
                             {
                                 Address = a.Address,
                                 Code = a.Code,
                                 Icon = a.Icon,
                                 Name = b.Value,
                                 ParentCode = a.ParentCode,
                                 Sequence = a.Sequence,
                                 Status = a.Status,
                                 AutoId = a.AutoId,
                                 CreatDate = a.CreatDate.HasValue ? a.CreatDate.Value.ToString("yyyy-MM-dd HH:mm") : "",
                                 Creator = a.Creator.HasValue ? a.Creator.Value.ToString() : ""
                             }).ToListAsync();
            else
                menus = await dbContext.BusinessDb.Queryable<MenuInfo>().
                     InnerJoin<MenuRole>((a, b) => a.AutoId == b.MenuId)
                     .InnerJoin<RoleEmployeeInfo>((a, b, c) => b.RoleId == c.RoleId)
                     .LeftJoin<MenuRes>((a, b, c, d) => a.AutoId == d.MenuId && d.Lan == lan)
                     .Where((a, b, c, d) => c.EmpId == userModel.EmpId)
                     .Select((a, b, c, d) => new MenuInfoListDto()
                     {
                         Address = a.Address,
                         Code = a.Code,
                         Icon = a.Icon,
                         Name = d.Value,
                         ParentCode = a.ParentCode,
                         Sequence = a.Sequence,
                         Status = a.Status,
                         AutoId = a.AutoId,
                         CreatDate = a.CreatDate.HasValue ? a.CreatDate.Value.ToString("yyyy-MM-dd HH:mm") : "",
                         Creator = a.Creator.HasValue ? a.Creator.Value.ToString() : ""
                     }).ToListAsync();
            List<MenuInfoListDto> resultMenuInfo = new List<MenuInfoListDto>();
            if (menus.Any())
            {
                foreach (var item in menus.OrderBy(o => o.Sequence).Where(O => string.IsNullOrEmpty(O.ParentCode)))
                {
                    List<BussineKeyValueDto> dtos = JsonConvert.DeserializeObject<List<BussineKeyValueDto>>(item.Icon);
                    if (dtos.Any(o => o.Label == "pc"))
                    {
                        item.IconKind = (PackIconKind)int.Parse(dtos.FirstOrDefault(o => o.Label == "pc").Value ?? "0");
                    }
                    foreach (var oitem in menus.Where(o => o.ParentCode == item.Code))
                    {
                        dtos = JsonConvert.DeserializeObject<List<BussineKeyValueDto>>(oitem.Icon);
                        if (dtos.Any(o => o.Label == "pc"))
                        {
                            oitem.IconKind = (PackIconKind)int.Parse(dtos.FirstOrDefault(o => o.Label == "pc").Value ?? "0");
                        }
                        foreach (var tItem in menus.Where(o => o.ParentCode == oitem.Code))
                        {
                            dtos = JsonConvert.DeserializeObject<List<BussineKeyValueDto>>(tItem.Icon);
                            if (dtos.Any(o => o.Label == "pc"))
                            {
                                tItem.IconKind = (PackIconKind)int.Parse(dtos.FirstOrDefault(o => o.Label == "pc").Value ?? "0");
                            }
                            foreach (var fItem in menus.Where(o => o.ParentCode == tItem.Code))
                            {
                                dtos = JsonConvert.DeserializeObject<List<BussineKeyValueDto>>(fItem.Icon);
                                if (dtos.Any(o => o.Label == "pc"))
                                {
                                    fItem.IconKind = (PackIconKind)int.Parse(dtos.FirstOrDefault(o => o.Label == "pc").Value ?? "0");
                                }
                                tItem.Childs.Add(fItem);
                            }
                            oitem.Childs.Add(tItem);
                        }
                        item.Childs.Add(oitem);
                    }
                    resultMenuInfo.Add(item);
                }
            }
            return resultMenuInfo;
        }

        /// <summary>
        /// 保存菜单信息数据
        /// </summary>
        /// <param name="menuInfoViewModel"></param>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        [GlobalLogAspect]
        public async Task<bool> SaveMenuInfo(MenuInfoViewModel menuInfoViewModel)
        {
            bool b = true;
            MenuInfo menuInfo = null;
            List<MenuRes> res = new List<MenuRes>();
            if (menuInfoViewModel.AutoId > 0)
            {
                menuInfo = await this.dbContext.BusinessDb.Queryable<MenuInfo>().FirstAsync(o => o.AutoId == menuInfoViewModel.AutoId);
                res = await this.dbContext.BusinessDb.Queryable<MenuRes>().Where(o => o.MenuId == menuInfoViewModel.AutoId).ToListAsync();
                menuInfo.Icon = new List<BussineKeyValueDto>() {
                    new BussineKeyValueDto() {
                        Label="pc",
                        Value=menuInfoViewModel.PackIconKind is null?"": menuInfoViewModel.PackIconKind.IconKind.GetHashCode().ToString()
                    }
                }.ToSafeJson();
                menuInfo.Address = menuInfoViewModel.Address;
                menuInfo.Modifier = userModel.EmpId;
                menuInfo.ModifDate = DateTime.Now;
                res.FirstOrDefault(o => o.Lan == 0).Value = menuInfoViewModel.Name;
                res.FirstOrDefault(o => o.Lan == 1).Value = menuInfoViewModel.EnName;
                var dbResult = await this.dbContext.BusinessDb.UseSugarTranAsync(async () =>
                {
                    await this.dbContext.BusinessDb.Updateable(menuInfo).ExecuteCommandAsync();
                    await this.dbContext.BusinessDb.Updateable(res).ExecuteCommandAsync();
                    await this.dbContext.BusinessDb.Ado.CommitTranAsync();
                    return true;
                });
                b = dbResult.IsSuccess;
            }
            else
            {
                var seq = this.dbContext.BusinessDb.Queryable<MenuInfo>().Where(o => string.IsNullOrEmpty(o.ParentCode)).Max(o => o.Sequence) + 1;
                menuInfo = menuInfoViewModel.Adapt<MenuInfo>();
                menuInfo.Modifier = userModel.EmpId;
                menuInfo.ModifDate = DateTime.Now;
                menuInfo.Creator = userModel.EmpId;
                menuInfo.CreatDate = DateTime.Now;
                menuInfo.Status = true;
                menuInfo.Icon = new List<BussineKeyValueDto>() {
                    new BussineKeyValueDto() {
                        Label="pc",
                        Value= menuInfoViewModel.PackIconKind is null?"":menuInfoViewModel.PackIconKind.IconKind.GetHashCode().ToString()
                    }
                }.ToSafeJson();
                menuInfo.Sequence = seq;
                try
                {
                    await this.dbContext.BusinessDb.Ado.BeginTranAsync();
                    long id = await this.dbContext.BusinessDb.Insertable(menuInfo).ExecuteReturnBigIdentityAsync();
                    res.Add(new MenuRes() { Lan = 0, Value = menuInfoViewModel.Name, MenuId = id });
                    res.Add(new MenuRes() { Lan = 1, Value = menuInfoViewModel.EnName, MenuId = id });
                    await this.dbContext.BusinessDb.Insertable(res).ExecuteCommandAsync();
                    await this.dbContext.BusinessDb.Ado.CommitTranAsync();
                }
                catch (Exception)
                {
                    await this.dbContext.BusinessDb.Ado.RollbackTranAsync();
                    b = false;
                }
            }
            return b;
        }
    }
}
